<template>
  <Sphere ref="SphereRef" :args="[0.3]">
    <TresMeshToonMaterial :color="getColor()" />
    <Suspense>
      <TresSprite :position="getPosition()" :rotation-x="Math.PI / 2">
        <TresSpriteMaterial :map="getTextTexture()" transparent :alpha-test="0.1" />
      </TresSprite>
    </Suspense>
    <Line2 v-if="isShowLine || showLine" dashed :gap-size="0.5" :dash-size="0.5" :points="getLines()" color="red" />
  </Sphere>
</template>
<script lang="ts" setup>
import { useTresContext, useRenderLoop } from '@tresjs/core'
import { Sphere, Line2 } from '@tresjs/cientos'
import * as THREE from 'three'
import { Pointer } from '@/graph/3d/config/shapes'
import { use3DEditorStore, useFormulaEditor } from '@/store'
import { storeToRefs } from 'pinia'
import Utils from '@/graph/3d/utils'

const props = defineProps<{ data: Pointer; showLine?: boolean }>()

const editorStore = use3DEditorStore()
const formulaEditor = useFormulaEditor()
const { mouseVector, isEditing, isCreating } = storeToRefs(editorStore)
const context = useTresContext()
const { onLoop } = useRenderLoop()
const SphereRef = shallowRef<InstanceType<typeof Sphere>>()
const isShowLine = shallowRef(false)

// 替换为普通函数
function getColor() {
  return props.data.activeted
    ? '#cee1f5'
    : !props.data.canMove
      ? '#918e8e'
      : '#1486fa'
}

function getPosition() {
  const origin = new THREE.Vector3(...props.data.position)
  const offset = new THREE.Vector3(...props.data.offset)
  return new THREE.Vector3().addVectors(origin, offset).toArray()
}

function getLines() {
  const distance = (props.data.position[2] + props.data.offset[2]) * -1
  return [
    [0, 0, 0],
    [0, 0, distance],
  ] as VerticesType[]
}

const curElement = computed(() => {
  // @ts-ignore
  return formulaEditor.elements.find((item) => item.id === props.data.toRef)
})

onLoop(() => {
  SphereRef.value?.instance.position.set(...getPosition())
  if (curElement.value && SphereRef.value) {
    SphereRef.value.instance.visible = curElement.value.visible
  }
})

// TODO 水平垂直移动时鼠标指针与顶点不能重合，视觉出现偏差
const page = {
  isMove: false,
  click() {
    if (page.isMove) return
    const direction = props.data.direction ? 0 : 1
    formulaEditor.updatePointer([
      {
        id: props.data.id,
        formulaId: props.data.formulaId,
        activeted: true,
        direction,
      },
    ])
  },
  down(e: any) {
    if (!props.data.canMove) return
    editorStore.setEditing(true)

    const p1 = Utils.screenToWebGL(
      e.clientX,
      e.clientY,
      context.renderer.value.domElement,
      3,
    ) as THREE.Vector3
    const diff = new THREE.Vector3()
    const offset = props.data.offset

    const move = (e: PointerEvent) => {
      if (!isEditing.value) return
      page.isMove = true
      isShowLine.value = true
      const _offset = new THREE.Vector3()

      if (props.data.direction === 0) {
        const v1 = Utils.screenToWebGL(
          e.clientX,
          e.clientY,
          context.renderer.value.domElement,
          3,
        ) as THREE.Vector3
        diff.subVectors(v1, p1)
        _offset.set(offset[0], offset[1], diff.y * 20)
      }
      else {
        const v1 = new THREE.Vector3(...mouseVector.value)
        const v2 = new THREE.Vector3(...props.data.position)
        const diff = v1.sub(v2)
        _offset.set(diff.x, diff.y, offset[2])
      }
      formulaEditor.updatePointer([
        {
          id: props.data.id,
          formulaId: props.data.formulaId,
          offset: _offset.toArray(),
        },
      ])
    }
    const up = () => {
      setTimeout(() => {
        page.isMove = false
      }, 100)

      if (isEditing.value) {
        formulaEditor.updatePointer([
          {
            id: props.data.id,
            formulaId: props.data.formulaId,
            position: [...getPosition()],
          },
        ])
      }
      isShowLine.value = false
      formulaEditor.updatePointer([
        {
          id: props.data.id,
          formulaId: props.data.formulaId,
          offset: [0, 0, 0],
        },
      ])
      editorStore.setEditing(false)

      document.removeEventListener('pointermove', move)
      document.removeEventListener('mouseup', up)
    }

    document.addEventListener('pointermove', move)
    document.addEventListener('mouseup', up)
  },
  enter() {
    if (isCreating.value || isEditing.value) return
    formulaEditor.updatePointer([
      { id: props.data.id, formulaId: props.data.formulaId, hovered: true },
    ])
  },
  leave() {
    if (isCreating.value || isEditing.value) return
    formulaEditor.updatePointer([
      { id: props.data.id, formulaId: props.data.formulaId, hovered: false },
    ])
  },
  handleKeyDown(e: KeyboardEvent) {
    if (e.key === 'Delete') {
      if (isEditing.value || props.data.activeted) {
        formulaEditor.removeElement(props.data.formulaId!)
        editorStore.setEditing(false)
      }
    }
    if (e.key === 'Escape') {
      editorStore.setEditing(false)
      formulaEditor.updatePointer([
        {
          id: props.data.id,
          formulaId: props.data.formulaId,
          offset: [0, 0, 0],
        },
      ])
    }
  },
}

onMounted(() => {
  document.addEventListener('keydown', page.handleKeyDown)
})
onBeforeUnmount(() => {
  document.removeEventListener('keydown', page.handleKeyDown)
})

function getTextTexture() {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
  ctx.font = '20px Arial'
  const width = ctx.measureText(props.data.name).width + 10
  canvas.width = width
  canvas.height = 30
  ctx.fillStyle = 'rgba(0,0,0,0)' // 设置透明背景
  ctx.fillRect(0, 0, width, 30)
  ctx.fillStyle = `rgb(20, 134, 250)`
  ctx.fillText(props.data.name, 5, 20)

  return new THREE.CanvasTexture(canvas)
}
</script>